#include "header.h"

data_base::data_base(unsigned char get_type):
    var_type(get_type),
    data_count(0)
{
    switch(var_type)
    {
    case DATA_CHAR:
        var_size = sizeof(char);
        break;
    case DATA_INT:
        var_size = sizeof(int);
        break;
    case DATA_FLOAT:
        var_size = sizeof(float);
        break;
    case DATA_DOUBLE:
        var_size = sizeof(double);
        break;
    default:
        std::cout << "Error: Invalid Var_Type!" << std::endl;
        var_size = 0;
        break;
    }
}

int data_base::get_data_count()
{
    return data_count;
}

int data_base::set_data_count(int set_count)
{
    data_count = set_count;
    return data_count;
}

int data_base::get_data_type()
{
    return var_type;
}
int data_base::set_data_type(int set_type)
{
    var_type = set_type;
    return var_type;
}

data_stack::data_stack(unsigned char var_type):
    data_base(var_type),
    stack_buffer(NULL),
    stack_buffer_size(0)
{
    stack_top = new VARANT;
    stack_top->var_type = get_data_type();
    stack_top->var_char = NULL;
}
data_base::~data_base()
{

}
LPVARANT data_stack::get_top_element()
{
    if(!stack_top->var_char)
        return NULL;
    return stack_top;
}

bool data_stack::enlarge_buffer()
{
    void* temp;
    if(stack_buffer_size == 0)
    {
        if(!(stack_buffer = malloc(500)))
            return false;
        memset(stack_buffer,0,500);
        stack_buffer_size += 500;
        stack_top->var_char = NULL;
    }
    else
    {
        temp = stack_buffer;
        if(!(stack_buffer = malloc(stack_buffer_size + 500)))
            return false;
        stack_buffer_size += 500;
        memset(stack_buffer,0,stack_buffer_size + 500);
        if(!memcpy(stack_buffer + stack_buffer_size,temp,stack_buffer_size))
            return false;
        free(temp);
        stack_top->var_char = (char*)stack_buffer + var_size * data_count;
    }
    return true;
}

LPVARANT data_stack::in_stack(LPVARANT in_data)
{
    if( get_data_type() != in_data->var_type)
    {
        std::cout << "Error: Invalid var_type!" << std::endl;
        return NULL;
    }

    if(var_size*(data_count+1) > stack_buffer_size)
    {
        enlarge_buffer();
    }
    data_count++;
    switch(get_data_type())
    {
    case DATA_CHAR:
        if(stack_top->var_char)
            (stack_top->var_char)++;
        else
        {
            stack_top->var_char = (char*)stack_buffer;
        }
        *(stack_top->var_char) = *(in_data->var_char);
        return in_data;
    case DATA_INT:
        if(stack_top->var_int)
            (stack_top->var_int)++;
        else
        {
            stack_top->var_int = (int*)stack_buffer;
        }
        *(stack_top->var_int) = *(in_data->var_int);
        return in_data;
    case DATA_FLOAT:
        if(stack_top->var_float)
            (stack_top->var_float)++;
        else
        {
            stack_top->var_float = (float*)stack_buffer;
        }
        *(stack_top->var_float) = *(in_data->var_float);
        return in_data;
    case DATA_DOUBLE:
        if(stack_top->var_double)
            (stack_top->var_double)++;
        else
        {
            stack_top->var_double = (double*)stack_buffer;
        }
        *(stack_top->var_double) = *(in_data->var_double);
        return in_data;
    default:
        std::cout << "Error!" << std::endl;
        return NULL;
    }
}

LPVARANT    data_stack::out_stack()
{
    LPVARANT re_varant = (LPVARANT)malloc(sizeof(VARANT));
    if(!stack_top->var_char)
        return NULL;
    re_varant->var_type = stack_top->var_type;
    switch(get_data_type())
    {
    case DATA_CHAR:
        re_varant->var_char = (char*)malloc(sizeof(char));
        *(re_varant->var_char) = *(stack_top->var_char);
        if(data_count)
        {
            (stack_top->var_char)--;
        }
        else
        {
            stack_top->var_char = NULL;
        }
        data_count--;
        break;
    case DATA_INT:
        re_varant->var_int = (int*)malloc(sizeof(int));
        *(re_varant->var_int) = *(stack_top->var_int);
        if(data_count)
        {
            (stack_top->var_int)--;
        }
        else
        {
            stack_top->var_int = NULL;
        }
        data_count--;
        break;
    case DATA_FLOAT:
        re_varant->var_float = (float*)malloc(sizeof(float));
        *(re_varant->var_float) = *(stack_top->var_float);
        if(data_count)
        {
            (stack_top->var_float)--;
        }
        else
        {
            stack_top->var_float = NULL;
        }
        data_count--;
        break;
    case DATA_DOUBLE:
        re_varant->var_double = (double*)malloc(sizeof(double));
        *(re_varant->var_double) = *(stack_top->var_double);
        if(data_count)
        {
            (stack_top->var_double)--;
        }
        else
        {
            stack_top->var_double = NULL;
        }
        data_count--;
        break;
    default:
        std::cout << "Error!" << std::endl;
        return NULL;
    }
    return re_varant;
}

data_stack::~data_stack(){

}
